package com.lkdont.android.media.recorder

import com.lkdont.android.media.MediaException

/**
 * 录制器基类
 *
 * @author lqd
 */
abstract class BaseRecorder : Recorder {

    /*** 录制状态 */
    var state: RecordState = RecordState.INITIAL
        private set

    /*** 是否录制中 */
    val isRecording: Boolean
        get() {
            return (state == RecordState.RECORDING)
        }

    protected abstract fun prepareRecorder()

    @Synchronized
    override fun prepare() {
        checkState(RecordState.PREPARED, "当前状态($state)不能调用prepare方法")
        prepareRecorder()
        changeState(RecordState.PREPARED)
    }

    protected abstract fun startRecorder()

    @Synchronized
    override fun start() {
        checkState(RecordState.RECORDING, "当前状态($state)不能调用start方法")
        startRecorder()
        changeState(RecordState.RECORDING)
    }

    /*** 停止录制，此方法不改变状态 */
    protected abstract fun stopRecorder()

    @Synchronized
    override fun stop() {
        checkState(RecordState.INITIAL, "当前状态($state)不能调用stop方法")
        stopRecorder()
        resetRecorder()
        isPausing = false
        changeState(RecordState.INITIAL)
    }

    /*** 是否暂停中 */
    var isPausing: Boolean = false
        private set

    protected abstract fun pauseRecorder()

    @Synchronized
    override fun pause() {
        if (state != RecordState.RECORDING) {
            throw IllegalStateException("当前状态($state)不能调用pause方法")
        }
        if (isPausing) {
            return
        }
        pauseRecorder()
        isPausing = true
    }

    protected abstract fun resumeRecorder()

    @Synchronized
    override fun resume() {
        if (state != RecordState.RECORDING) {
            throw IllegalStateException("当前状态($state)不能调用resume方法")
        }
        if (isPausing) {
            return
        }
        resumeRecorder()
        isPausing = false
    }

    protected abstract fun resetRecorder()

    @Synchronized
    override fun reset() {
        checkState(RecordState.INITIAL, "当前状态($state)不能调用reset方法")
        // 确保已经停止录制
        if (isRecording) {
            stopRecorder()
        }
        resetRecorder()
        isPausing = false
        changeState(RecordState.INITIAL)
    }

    /*** 是否已经释放资源 */
    val isReleased: Boolean
        get() {
            return (state == RecordState.RELEASED)
        }

    protected abstract fun releaseRecorder()

    @Synchronized
    override fun release() {
        checkState(RecordState.RELEASED, "当前状态($state)不能调用release方法")
        // 确保已经停止录制
        if (isRecording) {
            stopRecorder()
        }
        releaseRecorder()
        isPausing = false
        changeState(RecordState.RELEASED)
    }

    //******************************** 事件回调 ********************************//

    private var eventListener: RecordEventListener? = null

    override fun setRecordEventListener(listener: RecordEventListener?) {
        eventListener = listener
    }

    /*** 发生错误 */
    protected fun onError(msg: String) {
        if (state == RecordState.RECORDING) {
            stopRecorder()
        }
        changeState(RecordState.ERROR)
        eventListener?.onError(this, MediaException(msg))
    }

    /**
     * 检查状态能不能被改变为[newState]，如果不能则抛出错误[errorMsg]
     */
    protected fun checkState(newState: RecordState, errorMsg: String) {
        if (state == RecordState.RELEASED) {
            // 录制器已经释放，不能再执行其它操作
            throw IllegalStateException(errorMsg)
        }
        if (newState == RecordState.INITIAL || newState == RecordState.ERROR || newState == RecordState.RELEASED) {
            // 任何状态下都可以重置或者可能发生错误
            return
        }
        val error = when (state) {
            RecordState.INITIAL -> {
                newState != RecordState.INITIALIZED
            }
            RecordState.INITIALIZED -> {
                newState != RecordState.PREPARED
            }
            RecordState.PREPARED -> {
                newState != RecordState.RECORDING
            }
            else -> true
        }
        if (error) {
            throw IllegalStateException(errorMsg)
        }
    }

    /*** 改变状态，改变前先调用[checkState]保证状态能正常改变 */
    protected open fun changeState(newState: RecordState) {
        val oldState = state
        state = newState
        eventListener?.onStateChanged(this, oldState, newState)
    }
}